/*!
 * events 事件处理机制
 */
import { getOpt, isString } from './opts'
import { getWorker } from './tasks'

export default class EventManager {
  form = null
  rules = {} // 事件定义
  properties = {
    "data": "data"
  }
  name =  null
  values = null

  /**
   * constructor 原型
   * @param { Object } this -- 当前form表单的vue实例
   * @param { Object } properties -- 属性参数名（用于兼容pc/mobile字段名不同的问题）
   * @description   properties -- 如：在pc端，用来获取rules的数组controls取自this.form.options.data，那么移动可以设置 property = {"data": "meta"}
   */
  constructor(form, property) {
    this.form = form
    this.properties = Object.assign(this.properties, property)
    this.init()
  }

  init() {
    const rules = this.rules = {}
    const controls = this.form.options[this.properties.data]

    controls.forEach(item => {
      if (item.events) {
        const events = isString(item.events) ? JSON.parse(item.events) : item.events
        events.forEach(evt => {
          const itemRules = rules[item.name] || (rules[item.name] = [])
          itemRules.push(evt)
        })
      }
      if (item.dataLinkage) { // 事件扩展
        const dataLinkage = isString(item.dataLinkage) ? JSON.parse(item.dataLinkage) : item.dataLinkage
        dataLinkage.forEach(evt => {
          const itemRules = rules[item.name] || (rules[item.name] = [])
          itemRules.push(evt)
        })
      }
    })
  }

  /**
   * @method checkEvent 
   * @description 事件发生时检查是否需要处理
   * @param { String } type -- 事件触发方式
   * @param { String } name -- 当前事件触发的表单名称
   * @param { Object } values -- 当前事件触发的表单值，格式： { "name": xxxx }
   */
  checkEvent(type, name, values) {
    const rules = this.rules[name];
    this.name = name;
    this.values = values;
    if (rules && rules.length > 0) {
      rules.forEach(rule => {
        if (rule.triggerType === type) {
          this.processEvent(rule, name)
        }
      })
    }
  }

  /**
   * @method processEvent 
   * @description 事件处理
   * @param { Object } rule -- 事件规则
   * @param { String } currentName -- 当前事件触发的表单名称
   */
  processEvent(rule, currentName) {
    const { relationType, groups, tasks, refAction } = rule
    const conditions = {
      relationType,
      conditions: groups
    }
    // refAction 用于数据联动
    let valid = this.validate(conditions);
    if(!refAction && !valid) return
    this.doTasks(tasks, currentName)
  }

  /**
   * @method getValue 
   * @description 获取当前表单值
   * @return
   */
  getValue() {
    return this.values && this.values[this.name]
  }

  /**
   * @method validate
   * @description 校验条件是否满足规定
   * @return {Boolean}
   */
  validate(rule) {
    const { relationType, conditions, name, value, compareType } = rule

    if (relationType) { // 集合规则
      if(relationType === "release"){
        return true
      }else{
        const isOr = relationType === 'or'
        return isOr ?
          conditions.some(item => this.validate(item)) :
          conditions.every(item => this.validate(item))
      }
    } else if (name && compareType) {
      const current = this.getValue()
      return getOpt(compareType).caculate(current, value)
    } else {
      console.warn('error check conditions: ', rule)
      return false
    }
  }

  /**
   * @method doTasks
   * @description 执行事件触发的任务
   * @param { Array } tasks -- 事件规则
   * @param { String } currentName -- 当前事件触发的表单名称
   */
  doTasks(tasks, currentName) {
    //  task 格式 { "name":"申请人", "propName":"visible", "propValue":false }
    //  name -- 干预表单项名称； propName -- 干预类型名称(visible/required/equal)； propValue -- 干预类型结果
    tasks.forEach(({ name, propName, propValue }) => {
      const Worker = getWorker(propName, name)
      if (Worker) {
        const worker = new Worker(this.form, name, propValue)
        worker.run(currentName, propValue)
      } else {
        console.warn('no proper worker ', propName)
      }
    })
  }
}